package com.qust.agreement;

import com.alibaba.fastjson2.JSON;
import com.qust.agreement.Enums.SerializationEnum;
import com.qust.exception.SerializationException;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageCodec;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * 传输协议
 */
public class EnDecAgreement extends ByteToMessageCodec<Message> {
    private final int version = 0;

    /**
     * 编码
     * @param channelHandlerContext
     * @param message
     * @param byteBuf
     * @throws Exception
     */
    @Override
    public void encode(ChannelHandlerContext channelHandlerContext, Message message, ByteBuf byteBuf) throws Exception {
        byteBuf.writeBytes(new byte[]{'f','a','n','!'}); // 魔数,4
        byteBuf.writeInt(version); // 版本号,4
        byteBuf.writeInt(message.getSerialization()); // 获取序列化方式,4
        byteBuf.writeInt(message.getInstruction()); // 获取指令,4
        // 16 字节
        byte[] bytes = getSerializationOfInstance(message.getContext(),message.getSerialization()); // 获取序列化对象
        byteBuf.writeInt(bytes.length); // 写入长度
        byteBuf.writeBytes(bytes); // 写入内容
    }

    /**
     * 解码
     * @param channelHandlerContext
     * @param byteBuf
     * @param list
     * @throws Exception
     */
    @Override
    public void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
        Message message = new Message();
        byteBuf.readInt(); // 魔数
        System.out.println();
        byteBuf.readInt(); // 版本号
        message.setSerialization(byteBuf.readInt()); // 序列化
        message.setInstruction(byteBuf.readInt()); // 指令
        int len = byteBuf.readInt();// 长度
        byte[] bytes = new byte[len];
        byteBuf.readBytes(bytes);
        message.setContext(getInstanceFromSerialization(bytes,message.getSerialization()));
        list.add(message);
    }

    /**
     *  实例转序列化<br/>
     *  注意: 以后可以使用策略模式实现
     * @param obj 实例
     * @param code 序列化编号
     * @return 序列化比特数组
     * @throws SerializationException 没有此序列化
     */
    private byte[] getSerializationOfInstance(Object obj,int code) throws SerializationException {
        if (code == SerializationEnum.json.getCode()){
            return JSON.toJSONBytes(obj);
        }else if (code == SerializationEnum.java.getCode()) {
            try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
                 ObjectOutputStream oos = new ObjectOutputStream(bos);) {

                oos.writeObject(obj);
                return bos.toByteArray();
            } catch (IOException e) {
                System.out.println(e.getMessage());
                throw new RuntimeException(e);
            }
        }else if(code == SerializationEnum.string.getCode()){
            String s = (String) obj;
            return s.getBytes(StandardCharsets.UTF_8);
        }else {
            throw new SerializationException();
        }
    }

    /**
     *  序列化转实例<br/>
     *  注意: 以后可以使用策略模式实现
     * @param bytes 序列化比特数组
     * @param code 序列化算法编号
     * @return 实例
     * @throws SerializationException 没有此序列化
     */
    private Object getInstanceFromSerialization(byte[] bytes,int code) throws SerializationException {
        if (code == SerializationEnum.string.getCode()){
            return new String(bytes);
        }else if (code == SerializationEnum.json.getCode()){
            return JSON.parseObject(new String(bytes));
        } else if (code == SerializationEnum.java.getCode()) {
            try( ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));){
                return ois.readObject();
            } catch (IOException | ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        } else if (code == SerializationEnum.Byte.getCode()) {
            return bytes;
        } else {
            throw new SerializationException();
        }
    }
}
